package ecop017;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.Random;
import javax.swing.JPanel;

public class Ecopia extends JPanel {
    
    private final Shape mtn, coast, wHills, eHills, valley;  // Ecopia ecozones.
    private final Shape nsDivision, weDivision; // Player/Quadrant divisions.
    private final Sector [] sectors;
    private final EcoZone[] ecoZones;
    
     //  When > 1.0, new camp is added.
    
    //  Countdown variables.
    private static final int IYEARS = 1000;  // Maximum years game will run.
    private int yearsAgo = IYEARS;  //  Years left for game to run.
    private int yearsPassed = 0;  //  Number of years game has been running.

    protected static Random random = new Random();  // Random number generator.

    private long       lastUpdate = System.nanoTime();
    // nanoseconds between graphic updates (1 billion / s)
    private final long frequency  = 100000000;  
    private boolean    running    = true;
    
    //  Political Fund variables.
    private double [][] poliFund;
    private boolean [] feast;
    Shape warRect1, warRect2, warRect3;
    private double [] popRatePart;
    protected static Font myFont = new Font("Serif", Font.PLAIN, 20);
    protected static FontMetrics fontMetrics;

    //  sectorXY, holds the sector coordinates,centers, and CC1.
    static int [][] sectorXY=      {
    //    x     y     w     h    xc    yc  cC1
       {  2,    0,  446,   96,  225,   50,  18},   // mtn1.
       {  2,  100,  296,  247,  150,  225,  24},   // wHills1.
       {302,  100,  146,  247,  375,  225,  12},   // valley1.
       {452,    0,  446,   96,  675,   50,  18},   // mtn2.
       {602,  100,  296,  247,  750,  225,  24},   // eHills2.
       {452,  100,  146,  247,  525,  225,  12},   // valley2.
       {  2,  600,  446,   96,  225,  650,  18},   // coast3.
       {  2,  350,  296,  247,  150,  475,  24},   // wHills3.
       {302,  350,  146,  247,  375,  475,  12},   // valley3.
       {452,  600,  446,   96,  675,  650,  18},   // coast4.
       {602,  350,  296,  247,  750,  475,  24},   // eHills4.
       {452,  350,  146,  247,  525,  475,  12}    // valley4.
    };

    Ecopia () {
        super();
        this.setFocusable(true);
        this.setPreferredSize(new Dimension(900,800));
        this.setOpaque(true);
        this.setBackground(Color.WHITE);
        this.setVisible(true);
        this.validate();
        
        // set up our "global" FontMetrics so we can position text
        fontMetrics = this.getFontMetrics(myFont);

        //  Initialize ecozones.
        ecoZones = new EcoZone[5];
        mtn    = new Rectangle2D.Float(0, 0, 900, 100);
        coast  = new Rectangle2D.Float(0, 600, 900, 100);
        wHills = new Rectangle2D.Float(0, 100, 299, 499);
        eHills = new Rectangle2D.Float(600, 100, 300, 499);
        valley = new Rectangle2D.Float(300, 100, 299, 500);

        ecoZones[0] = new EcoZone("Mountains",  mtn,    new Color (225, 150, 225));
        ecoZones[1] = new EcoZone("Coast",      coast,  new Color (150, 150, 250));
        ecoZones[2] = new EcoZone("West Hills", wHills, new Color (200, 250, 150));
        ecoZones[3] = new EcoZone("East Hills", eHills, new Color (200, 250, 150));
        ecoZones[4] = new EcoZone("Valley",     valley, new Color (  0, 250,   0));

        //  Quadrants/Players.
        nsDivision = new Line2D.Float(450, 0, 450, 700);
        weDivision = new Line2D.Float(0, 350, 900, 350);

        sectors = new Sector[12];

        //  Initialize sectors[].
        for(int n = 0; n < 12; n++)  {
          sectors[n] = new Sector(sectorXY[n]);
        }
        
        //  Initialize popRatePart[].
        popRatePart = new double [12];
        for(int n = 0; n < 12; n++) { 
        popRatePart[n] = 0.0;        }
        
        //  Initialize poliFund[][].
        poliFund = new double[12][3]; feast = new boolean[12];
        for(int i=0; i < 12; i++)  {
            poliFund[i][0] = 0.0;  //  politicalFund.
            poliFund[i][1] = 0.8;  //  loyaltyIndex varies 0.0 < li < 1.0.
            poliFund[i][2] = 0.0;  //  warFund.
            feast[i] = false;
        }

        
       // Start the timer.
        Thread t = new Thread() {
          public void run() {  // Run method required by Thread object.
            gameLoop();
          }
        };
        t.start();
    }
    
    @Override
     public void paintComponent(Graphics g) {
       super.paintComponent(g);

       Graphics2D g2 = (Graphics2D)g;

       //  draw ecozones.
       for(EcoZone e : ecoZones) {
           e.paintBG(g2);
       }

       for(Sector thisSector : sectors) {
          thisSector.paint(g2);
        }
        
       //  Draw quadrant lines and labels.
        g2.setColor(Color.GRAY);
        g2.draw(nsDivision);
        g2.draw(weDivision);
        g2.setColor(Color.white);
        g2.setFont(myFont);
        g2.drawString("I",   50,  50);
        g2.drawString("II", 850,  50);
        g2.drawString("III", 50, 650);
        g2.drawString("IV", 850, 650);

       for(EcoZone e : ecoZones) {
           e.paintLabels(g2);
       }
        
       // Make countdown visible.
        g2.setColor(Color.black);     
        g2.drawString(yearsAgo + " Years Ago", 700, 740);

        //  Insert dummy attack.
        if(yearsAgo == 500)  {
            warRect1 = new Rectangle2D.Float(460, 225, 5, 5);
            warRect2 = new Rectangle2D.Float(455, 220, 5, 15);
            warRect3 = new Rectangle2D.Float(450, 215, 5, 25);
            g2.setPaint(Color.RED);
            g2.fill(warRect1);
            g2.fill(warRect2);
            g2.fill(warRect3);
        }    
        


   }  //  End of paintComponent.
     
   public void gameLoop() {  

     while(running) {
       update();
       try { Thread.sleep(1); }
       catch (InterruptedException ex) { }
       repaint();

    }
  }

  protected void update() {
      
    if(yearsAgo > 500) {  //count down to 500
      if((System.nanoTime() - lastUpdate) >= frequency) {
        lastUpdate = System.nanoTime();

        for(Sector s : sectors) {
          s.update();
        }


         //choose a random sector to examine
         /*
          * Problem:  some sectors are smaller than others, so they fill up
          * faster.  May be OK if we see this as getting a starting population
          * going.  We could let the sectors fill to, say, 70% of CC1, then
          * slow the pop growth rate to 1% in those sectors, letting the others
          * catch up.
          */
         int i = random.nextInt(sectors.length);

         // create a camp within the bounds of chosen sector
         Camp newCamp = new Camp(sectors[i].getBoundaries().getBounds2D());

         /*  Sort sector[i] camps at CC1 (only once).  (May not need this.)
         if(!sectors[i].sorted) {
             sectors[i].sortCamps();  */

         //  Change pop rate at CC1, and start Political Fund and Loyalty Index.
            //  At CC1, start Political Fund at 25% of camp.size.
            if ((sectors[i].carryCap1) == (sectors[i].camps.size())) 
                poliFund[i][0] = sectors[i].camps.size() * 0.25; 
         
           //  If below CC1, add a camp each year.
            if ((sectors[i].carryCap1) > (sectors[i].camps.size())) 
                sectors[i].addCamp(newCamp);

            else {        //  If above CC1 , add pop. at 1%/year.
                
                popRatePart[i] += (sectors[i].camps.size() * .01);
                if (popRatePart[i] > 1) {
                    sectors[i].addCamp(newCamp);
//                    sectors[i].setPoliticalFunds();
                    // Add 0.25 to politicalFund with each new camp.
                    poliFund[i][0] += 0.25; 
                    //  Subtract from politicalFund if feast given.
                        if(feast[i] == true)  {
                            poliFund[i][0] -= 3.0;
                            feast[i] = false;
                        }   
                //  Set loyaltyIndex (poliFund[i][1] to drop 5% with every additional camp over CC1.
                    poliFund[i][1] -= 0.05;
                  //If loyaltyIndex falls below 0,5, have a feast!
                    if(poliFund[i][1] < 0.5)  {
                        feast[i] = true; 
                        poliFund[i][1] += 0.3;
                    }
                   //sectors[i].sortCamps();  // wasnt sure if we need to re-sort after adding a new camp
                    popRatePart[i]--;  //  How does "--" work?  Why not popRatePart[i] -= 1.0?                  
                }
            }
       
        yearsAgo = yearsAgo-1;  //  Coming up to present time.
        if(yearsAgo == 501) {
            System.out.println("   CC1   camps.size    Political Fund   Loyalty Index(%)     Feast");
            for(int s = 0; s < 12; s++)
            System.out.println("   " + sectors[s].carryCap1 + "      " + sectors[s].camps.size() 
              + "            " + poliFund[s][0] + "                  " + ((int) (poliFund[s][1] * 100)) +
                    "            " + feast[s]);
        }
      }
    }
  }
}  
